//柯里化：把接受多个参数的函数变换成接受一个单一参数的函数,可以实现参数的依次传入,而不是一次性传入

//例:
// 普通的add函数
function add(x, y) {
    return x + y
}

// Currying后
function curryingAdd(x) {
    return function (y) {
        return x + y
    }
}

add(1, 2)           // 3
curryingAdd(1)(2)   // 3

//优势:最大的优势是可以进行函数复用，如下

// 正常正则验证字符串 reg.test(txt)
// 函数封装后
function check(reg, txt) {
    return reg.test(txt)
}

check(/\d+/g, 'test')       //false
check(/[a-z]+/g, 'test')    //true

// Currying后
function curryingCheck(reg) {
    return function(txt) {
        return reg.test(txt)
    }
}

var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

//如下，就避免了多次传入第一个相同的参数
//把携带相同参数的函数提取为变量，就可以实现复用
hasNumber('test1')      // true
hasNumber('testtest')   // false
hasLetter('21212')      // false

//比如实现如下效果:
// 实现一个add方法，使计算结果能够满足如下预期：
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;

function add() {
    // 第一次执行时，定义一个数组专门用来存储所有的参数
    var _args = [].slice.call(arguments);	//将类数组转换为数组
	
    // 在内部声明一个函数，利用闭包的特性保存_args并收集所有的参数值
    var _adder = function() {
		_args = _args.concat([].slice.call(arguments))	//也可以用_args.push(...arguments)
        return _adder;
    };

    // 利用toString隐式转换的特性，当最后执行时隐式转换，并计算最终的值返回
	// 使用隐式转换后，这里的_adder已经不是一个函数，而是一个字符串，而这个字符串就是reduce累加器的计算结果
    _adder.toString = function () {	
        return _args.reduce(function (a, b) {		//reduce累加器
            return a + b;
        });
    }
    return _adder;
}

//以下，无论怎么调用，都可以成功计算出结果
add(1)(2)(3)                // 6
add(1, 2, 3)(4)             // 10
add(1)(2)(3)(4)(5)          // 15
add(2, 6)(1)                // 9
add(2)(1, 6)                // 9